#include "modbus.h"

const u8 auchCRCHi[] =
{
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
    0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
    0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
    0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
    0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
};

const u8 auchCRCLo[] =
{
    0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
    0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
    0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
    0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
    0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
    0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
    0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
    0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
    0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
    0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
    0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
    0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
    0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
    0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
    0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
    0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
    0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
    0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
    0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
    0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
    0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
    0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
    0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
    0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
    0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
    0x43, 0x83, 0x41, 0x81, 0x80, 0x40
};

static void UART_config(void)
{
    COMx_InitDefine __xdata COMx_InitStructure;
    u16 __xdata baudrate;
    switch(sysParams.commBradrate)
    {
        case MODBUS_BAUDRATE_2400:
            baudrate = 2400;
        break;
        case MODBUS_BAUDRATE_4800:
            baudrate = 4800;
        break;
        case MODBUS_BAUDRATE_9600:
            baudrate = 9600;
        break;
        default://默认9600
            baudrate = 9600;
        break;
    }
    COMx_InitStructure.UART_Mode = UART_8bit_BRTx;
    COMx_InitStructure.UART_BRT_Use = BRT_Timer2;
    COMx_InitStructure.UART_BaudRate = baudrate;
    COMx_InitStructure.Morecommunicate = DISABLE;
    COMx_InitStructure.UART_RxEnable = ENABLE;
    COMx_InitStructure.BaudRateDouble = DISABLE;
    COMx_InitStructure.UART_Interrupt = ENABLE;
    COMx_InitStructure.UART_Priority = Priority_3;
    COMx_InitStructure.UART_P_SW = UART2_SW_P46_P47;
    UART_Configuration(UART2, &COMx_InitStructure);
}

static void GPIO_config(void)
{
    GPIO_InitTypeDef __xdata GPIO_InitStructure;        //结构定义
    GPIO_InitStructure.Pin = GPIO_Pin_2;        //指定要初始化的IO,
    GPIO_InitStructure.Mode = GPIO_OUT_PP;      //指定IO的输入或输出方式
    GPIO_Inilize(GPIO_P3, &GPIO_InitStructure); //初始化

    GPIO_InitStructure.Pin = GPIO_Pin_6 | GPIO_Pin_7;        //指定要初始化的IO,
    GPIO_InitStructure.Mode = GPIO_PullUp;      //指定IO的输入或输出方式
    GPIO_Inilize(GPIO_P4, &GPIO_InitStructure); //初始化
}

static void modbus_send_bytes(u8 *buf, u8 len)
{
    for(u8 __xdata i = 0; i < len; i++)
    {
        TX2_write2buff(buf[i]);
    }
}


static u16 modbus_crc16_calc(u8 *puchMsg, u8 usDataLen)
{
    u8 __xdata uchCRCHi = 0xFF ;              // 高CRC字节初始化  
    u8 __xdata uchCRCLo = 0xFF ;              // 低CRC 字节初始化

    u8 __xdata uIndex ;                      // CRC循环中的索引   
    
    while (usDataLen--)                  // 传输消息缓冲区  
    {
        uIndex = uchCRCHi ^ *puchMsg++ ; // 计算CRC         
        uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex];
        uchCRCLo = auchCRCLo[uIndex];
    }
    // TX1_write2buff(uchCRCLo);
    // TX1_write2buff(uchCRCHi);
    return (uchCRCHi << 8 | uchCRCLo);    // MODBUS 规定高位在前
}

void modbus_init(void)
{
    UART_config();
    GPIO_config();
    UART_DIR_RX();
}

void modbus_func(void)
{
    if(COM2.B_RX_OK) //接收到数据
    {
        u16 __xdata crc; 
        u8 __xdata buf[128];
        u8 __xdata len = 0;

        crc = modbus_crc16_calc(RX2_Buffer, COM2.RX_Cnt - 2);
        // modbus_send_bytes(RX2_Buffer, COM2.RX_Cnt);
        if(crc == ((RX2_Buffer[COM2.RX_Cnt - 2] << 8) | (RX2_Buffer[COM2.RX_Cnt - 1])))  //CRC校验
        {
        //     // PrintString1("succeeded\r\n");
            if(RX2_Buffer[0] == sysParams.commAddr)   //通讯地址匹配
            {
                u8 __xdata *pBuf = (u8 *)&sysParams.regs;
                u8 __xdata addrStart = RX2_Buffer[3];
                u8 __xdata regCnt = RX2_Buffer[5];
                switch(RX2_Buffer[1])  //功能码
                {
                    case 0x03:  //读寄存器
                    {
                        addrStart = RX2_Buffer[3];
                        regCnt = RX2_Buffer[5];
                        buf[len++] = sysParams.commAddr;
                        buf[len++] = 0x03;
                        buf[len++] = regCnt * 2;
                        
                        for(u8 __xdata i = 0; i < regCnt; i++)
                        {
                            switch(addrStart + i)
                            {
                                /* 室内温度寄存器 */
                                case 0:
                                {
                                    if(pBuf[addrStart + i] == 0xFF)     //当温度显示为0xFFFF(2个字节）时，表示传感器故障
                                        buf[len++] = 0xFF;
                                    else
                                        buf[len++] = 0;
                                    buf[len++] = pBuf[addrStart + i];
                                }
                                break;
                                /* 温度校正寄存器 */
                                case 15:
                                {
                                    buf[len++] = 0;
                                    if((signed char)pBuf[addrStart + i] >= 0)
                                        buf[len++] = pBuf[addrStart + i];
                                    else
                                        buf[len++] = (-pBuf[addrStart + i]) | 0x80;
                                }
                                break;
                                /* 回差下限寄存器 */
                                case 17:
                                {
                                    buf[len++] = 0;
                                    buf[len++] = (-pBuf[addrStart + i]) | 0x80;
                                }
                                break;
                                /* 其他寄存器 */
                                default:
                                {
                                    buf[len++] = 0;
                                    buf[len++] = pBuf[addrStart + i];
                                }
                                break;
                            }
                        }
                        crc = modbus_crc16_calc(buf, len);
                        buf[len++] = crc & 0xFF;
                        buf[len++] = crc >> 8;
                        modbus_send_bytes(buf, len);
                        break;
                    }

                    case 0x06:  //写单个寄存器
                    {
                        addrStart = RX2_Buffer[3];
                        u8 __xdata value = RX2_Buffer[5];
                        switch(addrStart)
                        {
                            /* 温度校正寄存器 */
                            case 15:
                            {
                                if(value & 0x80)
                                {
                                    pBuf[addrStart] = -(value & 0x7F);
                                }
                                else
                                {
                                    pBuf[addrStart] = (value & 0x7F);
                                }
                            }
                            break;
                            /* 回差下限寄存器 */
                            case 17:
                            {
                                if(value & 0x80)
                                {
                                    pBuf[addrStart] = -(value & 0x7F);
                                }
                                else
                                {
                                    pBuf[addrStart] = (value & 0x7F);
                                }
                            }
                            break;
                            /* 其他寄存器 */
                            default:
                            {
                                pBuf[addrStart] = value;
                            }
                            break;
                        }
                        pBuf[addrStart] = value;
                        buf[len++] = sysParams.commAddr;
                        buf[len++] = 0x06;
                        buf[len++] = 0x00;
                        buf[len++] = addrStart;
                        buf[len++] = 0x00;
                        buf[len++] = value;
                        crc = modbus_crc16_calc(buf, len);
                        buf[len++] = crc & 0xFF;
                        buf[len++] = crc >> 8;
                        modbus_send_bytes(buf, len);
                        break;
                    }
                        
                    case 0x10:  //写全部寄存器
                    {
                        addrStart = RX2_Buffer[3];
                        regCnt = RX2_Buffer[5];
                        for(u8 __xdata i = 0; i < regCnt; i++) 
                        {
                            switch(addrStart + i)
                            {
                                /* 温度校正寄存器 */
                                case 15:
                                {
                                    if(RX2_Buffer[8 + i * 2] & 0x80)
                                    {
                                        pBuf[addrStart + i] = -(RX2_Buffer[8 + i * 2] & 0x7F);
                                    }
                                    else
                                    {
                                        pBuf[addrStart + i] = (RX2_Buffer[8 + i * 2] & 0x7F);
                                    }
                                }
                                break;
                                /* 回差下限寄存器 */
                                case 17:
                                {
                                    if(RX2_Buffer[8 + i * 2] & 0x80)
                                    {
                                        pBuf[addrStart + i] = -(RX2_Buffer[8 + i * 2] & 0x7F);
                                    }
                                    else
                                    {
                                        pBuf[addrStart + i] = (RX2_Buffer[8 + i * 2] & 0x7F);
                                    }
                                }
                                break;
                                /* 其他寄存器 */
                                default:
                                {
                                    pBuf[addrStart + i] = RX2_Buffer[8 + i * 2];
                                }
                                break;
                            }
                        }
                        buf[len++] = sysParams.commAddr;
                        buf[len++] = 0x10;
                        buf[len++] = 0x00;
                        buf[len++] = addrStart;
                        buf[len++] = 0x00;
                        buf[len++] = regCnt;
                        crc = modbus_crc16_calc(buf, len);
                        buf[len++] = crc & 0xFF;
                        buf[len++] = crc >> 8;
                        modbus_send_bytes(buf, len);
                        break;
                    }
                    default:
                        break;
                }
            }
        }
        // else
        // {
        //     u16 __xdata temp = modbus_crc16_calc(RX2_Buffer, COM2.RX_Cnt - 2);
        //     PrintString1("failed\r\n");
        //     modbus_send_bytes(RX2_Buffer, COM2.RX_Cnt);
        //     buf[0] = temp & 0xFF;
        //     buf[1] = temp >> 8;
        //     buf[2] = 0;
        //     PrintString1(buf);
        // }
        COM2.RX_Cnt = 0;
        COM2.B_RX_OK = 0;
    }
}
